﻿/// <reference path="PerformanceTesterBase.ts" />
/// <reference path="..\TsLinq.d.ts" />
/// <reference path="..\KeyValuePair.ts" />
/// <reference path="..\Dictionary.ts" />   
/// <reference path="..\Linq.ts" />
/// <reference path="..\..\Scripts\linq.js.d.ts" />

class LinqTester extends PerformanceTesterBase implements ITester {

    bigNumbers: IEnumerable<number>;
    bigArray: number[];
    bigLinqJs: linqjs.Enumerable;

    constructor(logger: ILogger) {
        super(logger);
        this.bigArray = <number[]>[];
        for (var i = 0; i <= 10000000; i++) {
            this.bigArray.push(i);
        }
        this.bigNumbers = new Linq(this.bigArray);
        this.bigLinqJs = Enumerable.from(this.bigArray);
    }

    linq_where() {
        this.testPerformance('where(x%2==0)',
            () => this.bigNumbers.where(bn => bn % 2 == 0).count(),
            () => this.bigLinqJs.where(function (x) { return x % 2 == 0; }).count());
    }

    linq_single() {
        this.testPerformance('single(x == 10,000,000)',
            () => this.bigNumbers.single(bn => bn == 10000000),
            () => this.bigLinqJs.single(function (x) { return x == 10000000; }));
        this.testPerformance('single(x == 0)',
            () => this.bigNumbers.single(bn => bn == 0),
            () => this.bigLinqJs.single(function (x) { return x == 0; }));
    }

    linq_singleOrDefault() {
        this.testPerformance('singleOrDefault(x==10,000,000)',
            () => this.bigNumbers.singleOrDefault(bn => bn == 10000000),
            () => this.bigLinqJs.singleOrDefault(function (x) { return x == 10000000; }));
        this.testPerformance('singleOrDefault(x==0)',
            () => this.bigNumbers.singleOrDefault(bn => bn == 0),
            () => this.bigLinqJs.singleOrDefault(function (x) { return x == 0; }));
    }

    linq_all() {
        this.testPerformance('all(x<10,000,000)',
            () => this.bigNumbers.all(bn => bn < 10000000),
            () => this.bigLinqJs.all(function (x) { return x < 10000000; }));
        this.testPerformance('all(x<5,000,000)',
            () => this.bigNumbers.all(bn => bn < 5000000),
            () => this.bigLinqJs.all(function (x) { return x < 5000000; }));
    }

    linq_first() {
        this.testPerformance('first(x==10,000,000)',
            () => this.bigNumbers.first(bn => bn == 10000000),
            () => this.bigLinqJs.first(function (x) { return x == 10000000; }));
        this.testPerformance('first(x==0)',
            () => this.bigNumbers.first(bn => bn == 0),
            () => this.bigLinqJs.first(function (x) { return x == 0; }));
    }

    linq_firstOrDefault() {
        this.testPerformance('firstOrDefault(x==10,000,000)',
            () => this.bigNumbers.firstOrDefault(bn => bn == 10000000),
            () => this.bigLinqJs.firstOrDefault(function (x) { return x == 10000000; }));
        this.testPerformance('firstOrDefault(x==0)',
            () => this.bigNumbers.firstOrDefault(bn => bn == 0),
            () => this.bigLinqJs.firstOrDefault(function (x) { return x == 0; }));
    }

    linq_last() {
        this.testPerformance('last(x==10,000,000)',
            () => this.bigNumbers.last(bn => bn == 10000000),
            () => this.bigLinqJs.last(function (x) { return x == 10000000; }));
        this.testPerformance('last(x==0)',
            () => this.bigNumbers.last(bn => bn == 0),
            () => this.bigLinqJs.last(function (x) { return x == 0; }));
    }

    linq_lastOrDefault() {
        this.testPerformance('lastOrDefault(x==10,000,000)',
            () => this.bigNumbers.lastOrDefault(bn => bn == 10000000),
            () => this.bigLinqJs.lastOrDefault(function (x) { return x == 10000000; }));
        this.testPerformance('lastOrDefault(x==0)',
            () => this.bigNumbers.lastOrDefault(bn => bn == 0),
            () => this.bigLinqJs.lastOrDefault(function (x) { return x == 0; }));
    }

    linq_select() {
        var counter = 0;
        this.testPerformance('select({value:x})',
            () => this.bigNumbers.select(n => { return { value: n }; }),
            () => this.bigLinqJs.select(n => { return { value: n }; }),
            (val: any) => { return val.count()+' entries'; });
    }

    linq_indexOf() {
        this.testPerformance('indexOf(10,000,000)',
            () => this.bigNumbers.indexOf(10000000),
            () => this.bigLinqJs.indexOf(function (x) { return x == 10000000; }));
    }

    linq_elementAt() {
        this.testPerformance('elementAt(10,000,000)',
            () => this.bigNumbers.elementAt(10000000),
            () => this.bigLinqJs.elementAt(10000000));
    }

    linq_elementAtOrDefault() {
        this.testPerformance('elementAtOrDefault(10,000,000)',
            () => this.bigNumbers.elementAtOrDefault(10000000),
            () => this.bigLinqJs.elementAtOrDefault(10000000));
    }

    linq_forEach() {
        var todo = (item) => { };
        this.testPerformance('forEach({})',
            () => this.bigNumbers.forEach(todo),
            () => this.bigLinqJs.forEach(todo));
    }

    linq_contains() {
        this.testPerformance('indexOf(10,000,000)',
            () => this.bigNumbers.contains(10000000),
            () => this.bigLinqJs.contains(10000000, x => x));
    }

    linq_any() {
        this.testPerformance('any(x==10,000,000)',
            () => this.bigNumbers.any(bn => bn == 10000000),
            () => this.bigLinqJs.any(function (x) { return x == 10000000; }));
    }

    linq_count() {
        this.testPerformance('count(x==10000000)',
            () => this.bigNumbers.count(x => x == 10000000),
            () => this.bigLinqJs.count(function (x) { return x == 10000000; }));
    }

    linq_toDictionary() {
        this.testPerformance('toDictionary(x => x % 2)',
            () => this.bigNumbers.toDictionary(x => x % 2),
            () => this.bigLinqJs.toDictionary(x => x % 2),
            val => {
                return val.count() + ' keys generated';
            });
    }

    linq_groupBy() {
        this.testPerformance('groupBy(x => x % 2)',
            () => this.bigNumbers.groupBy(x => x % 2),
            () => this.bigLinqJs.groupBy(x => x % 2),
            val => {
                if (val === undefined) {
                    return '';
                }
                return val.count() + ' keys generated';
            });
    }

    linq_sum() {
        var takeArray = this.bigNumbers.take(1000000);
        this.testPerformance('sum(first 100000 entries) DOES NOT WORK IN LINQ.JS AS EXPECTED',
            () => takeArray.sum(),
            () => Enumerable.from(takeArray).sum());
        this.testPerformance('sum(first 100000 entries * 2) DOES NOT WORK IN LINQ.JS AS EXPECTED',
            () => takeArray.sum(x => x * 2),
            () => Enumerable.from(takeArray).sum(x => x * 2));
    }

    linq_selectMany() {
        var take = [{ values: this.bigNumbers.toArray() }, { values: this.bigNumbers.toArray() }];
        this.testPerformance('selectMany(2 objects with 10000001 values in property values)',
            () => new Linq(take).selectMany(v => v.values),
            () => Enumerable.from(take).selectMany(v => v.values),
            val => {
                return val.count()+' entries';
            });
    }

    linq_cast() {
        this._logger.debug('cast<>() was not implemented by Linq.js');
    }

    linq_aggregate() {
        this.testPerformance('aggregate((n1, n2) => n1 + n2)',
            () => this.bigNumbers.aggregate<number>((n1, n2) => n1 + n2),
            () => this.bigLinqJs.aggregate((n1, n2) => n1 + n2));
    }

    linq_skip() {
        this.testPerformance('skip(1,000,000)',
            () => this.bigNumbers.skip(1000000),
            () => this.bigLinqJs.skip(1000000),
            val => val.count()+' entries');
    }

    linq_take() {
        this.testPerformance('take(10,000,000)',
            () => this.bigNumbers.take(10000000),
            () => this.bigLinqJs.take(10000000),
            val => val.count() + ' entries');
    }

    linq_intersect() {
        var intersectWith = this.bigNumbers.take(10000).toArray();
        this.testPerformance('intersect(2 lists á 10000 entries)',
            () => new Linq(intersectWith).intersect(intersectWith),
            () => Enumerable.from(intersectWith).intersect(intersectWith),
            vals => vals.count() + ' entries');
    }

    linq_except() {
        var exceptWith = this.bigNumbers.take(10000).toArray();
        this.testPerformance('except(2 lists á 10000 entries)',
            () => new Linq(exceptWith).except(exceptWith),
            () => Enumerable.from(exceptWith).except(exceptWith),
            vals => vals.count() + ' entries');
    }

    linq_concat() {
        var concatWith = this.bigNumbers.take(10000).toArray();
        this.testPerformance('concat(with 10000 entries)',
            () => this.bigNumbers.concat(concatWith),
            () => this.bigLinqJs.concat(concatWith),
            vals => vals.count() + ' entries');
    }

    linq_reverse() {
        this.testPerformance('reverse()',
            () => this.bigNumbers.reverse(),
            () => this.bigLinqJs.reverse(),
            vals => vals.count() + ' entries');
    }

    linq_zip() {
        this.testPerformance('zip(addition of a collection of the same content)',
            () => this.bigNumbers.zip(this.bigArray, (i1, i2) => i1 + i2),
            () => this.bigLinqJs.zip(this.bigArray, (i1, i2) => i1 + i2),
            vals => vals.count() + ' entries');
    }

    linq_min() {
        this.testPerformance('min()',
            () => this.bigNumbers.min(),
            () => this.bigLinqJs.min());
        this.testPerformance('min(x*2)',
            () => this.bigNumbers.min(x => x*2),
            () => this.bigLinqJs.min(x => x * 2));
    }

    linq_max() {
        this.testPerformance('max()',
            () => this.bigNumbers.max(),
            () => this.bigLinqJs.max());
        this.testPerformance('max(x*2)',
            () => this.bigNumbers.max(x => x * 2),
            () => this.bigLinqJs.max(x => x * 2));
    }

    linq_distinct() {
        var arr = this.bigNumbers.select(x => x % 2).toArray();
        this.testPerformance('distinct(modulo from 2 of all items)',
            () => new Linq(arr).distinct(),
            () => Enumerable.from(arr).distinct(),
            vals => vals.count() + ' entries');
    }

    linq_union() {
        var arr = this.bigNumbers.take(10000).toArray();
        var tsLinq = new Linq(arr);
        var linqJs = Enumerable.from(arr);
        this.testPerformance('union(2 arrays á 10000 entries)',
            () => tsLinq.union(arr),
            () => linqJs.union(arr),
            vals => vals.count() + ' entries');
    }
} 